﻿using MCUPackage;
using MCUPackage.Utils;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SxPackages.STC8.Models
{
	/// <summary>
	/// 比较器选项
	/// </summary>
	[Serializable]
	class CMPOptions
	{
		protected STC8HUSOP20 mParent = null;

		private bool mEnable = false;
		[Category("比较器配置"),
		DisplayName("功能启用"),
		JsonProperty(Order = 100),
		Description("是否启用比较器功能"),
		DefaultValue(false)]
		public bool Enable
		{
			get => mEnable;
			set
			{
				if (value != mEnable)
				{
					if (value)
					{
						// 正端输入启用检查
						string[] pins = new string[] { mPositive.ToDescription(), mNegative.ToDescription(), mOut.ToDescription() };
						if (mParent.PinIsUsedTips(pins))
						{
							return;
						}
						SwitchPositive(mPositive, CMPPositive.ADC输入);
						SwitchNegative(mNegative, CMPNegative.内部参考电压);
						SwitchOut(mOut, CMPResultOut.不输出);
					}
					else
					{
						// 清除占用
						string oldName = mPositive.ToDescription();
						mParent.ResetPins(oldName);
						oldName = mOut.ToDescription();
						mParent.ResetPins(oldName);
					}
					mEnable = value;
				}
			}
		}

		/// <summary>
		/// 切换引脚
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="aNew"></param>
		/// <param name="aOld"></param>
		/// <returns></returns>
		private string SwitchPin<T>(T aNew, T aOld)
		{
			string newName = EnumUtils.GetDescription(aNew);
			string oldName = EnumUtils.GetDescription(aOld);
			var status = mParent.GetPinUsedString(newName);
			if (status != null)
			{
				// 引脚被占用
				GuiUtils.MsgBox(status);
				return null;
			}

			// 清理之前的引脚
			mParent.ResetPins(oldName);
			return newName;
		}

		/// <summary>
		/// 切换正端输入
		/// </summary>
		/// <param name="aNew"></param>
		/// <param name="aOldName"></param>
		/// <param name="aEnable"></param>
		/// <returns></returns>
		private bool SwitchPositive(CMPPositive aNew, CMPPositive aOld)
		{
			string name = SwitchPin(aNew, aOld);
			if (name == null)
			{
				// 引脚被占用
				return false;
			}

			// 设置新引脚
			var option = mParent.SetPinPurpose(name, PinPurpose.CMP_IN);
			if (option != null)
			{
				option.Mode = GPIOMode.HighInput;
				option.EnableIE = false;
			}
			return true;
		}

		private CMPPositive mPositive = CMPPositive.P37;
		[Category("比较器配置"),
		DisplayName("正端输入"),
		Description("比较器正端输入选择, 负端固定为内部参考电压"),
		DefaultValue(CMPPositive.P37)]
		public CMPPositive Positive
		{
			get => mPositive;
			set
			{
				if (value != mPositive)
				{
					if (this.Enable)
					{
						if (!SwitchPositive(value, mPositive))
						{
							return;
						}
					}
					mPositive = value;
				}
			}
		}

		/// <summary>
		/// 负端切换
		/// </summary>
		/// <param name="aNew"></param>
		/// <param name="aOld"></param>
		/// <returns></returns>
		private bool SwitchNegative(CMPNegative aNew, CMPNegative aOld)
		{
			string name = SwitchPin(aNew, aOld);
			if (name == null)
			{
				// 引脚被占用
				return false;
			}

			// 设置新引脚
			var option = mParent.SetPinPurpose(name, PinPurpose.CMP_NEGATIVE);
			if (option != null)
			{
				option.Mode = GPIOMode.HighInput;
				option.EnableIE = false;
			}
			return true;
		}

		private CMPNegative mNegative = CMPNegative.P36;
		[Category("比较器配置"),
		DisplayName("负端输入"),
		Description("比较器负端输入选择"),
		DefaultValue(CMPNegative.P36)]
		public CMPNegative Negative
		{
			get => mNegative;
			set
			{
				if (value != mNegative)
				{
					if (this.Enable)
					{
						if (!SwitchNegative(value, mNegative))
						{
							return;
						}
					}
					mNegative = value;
				}
			}
		}

		/// <summary>
		/// 切换输出引脚设置
		/// </summary>
		/// <param name="aNew"></param>
		/// <param name="aOldName"></param>
		/// <param name="aEnable"></param>
		/// <returns></returns>
		private bool SwitchOut(CMPResultOut aNew, CMPResultOut aOld)
		{
			string name = SwitchPin(aNew, aOld);
			if (name == null)
			{
				// 引脚被占用
				return false;
			}

			// 设置新引脚
			var option = mParent.SetPinPurpose(name, PinPurpose.CMP_OUT);
			if (option != null)
			{
				option.Mode = GPIOMode.Push;
			}

			return true;
		}

		private CMPResultOut mOut = CMPResultOut.P34;
		[Category("比较器配置"),
		DisplayName("结果输出"),
		Description("比较器结果输出引脚设置"),
		DefaultValue(CMPResultOut.P34)]
		public CMPResultOut Out
		{
			get => mOut;
			set
			{
				if (value != mOut)
				{
					if (this.Enable)
					{
						if (!SwitchOut(value, mOut))
						{
							return;
						}
					}
					mOut = value;
				}
			}
		}

		[Category("比较器配置"),
		DisplayName("输出取反"),
		Description("比较器结果是否进行反向输出"),
		DefaultValue(false)]
		public bool EnableReverse { get; set; } = false;

		[Category("比较器配置"),
		DisplayName("使能内部滤波"),
		Description("是否使能内部的0.1us滤波, 关闭滤波可略微提高比较速度"),
		DefaultValue(false)]
		public bool EnableFilter { get; set; } = false;

		private int mDelayDuty = 0;
		[Category("比较器配置"),
		DisplayName("数字滤波"),
		Description("数字信号去抖功能, 0则关闭该功能, 1~63滤波时间为设定值+2个系统时钟"),
		DefaultValue(0)]
		public int DelayDuty
		{
			get => mDelayDuty;
			set
			{
				if (value != mDelayDuty)
				{
					if (value < 0 || value > 63)
					{
						GuiUtils.MsgBox("请输入有效值!");
					}
					else
					{
						mDelayDuty = value;
					}
				}
			}
		}

		[Category("比较器配置"),
		DisplayName("使能上升沿中断"),
		Description("使能比较器的比较结果由0变为1时产生中断"),
		DefaultValue(false)]
		public bool EnablePTI { get; set; } = false;

		[Category("比较器配置"),
		DisplayName("使能下降沿中断"),
		Description("使能比较器的比较结果由1变为0时产生中断"),
		DefaultValue(false)]
		public bool EnableNTI { get; set; } = false;

		[Category("比较器配置"),
		DisplayName("中断优先级"),
		Description("中断优先级等级设置"),
		DefaultValue(PriorityTypes.最低级)]
		public PriorityTypes Priority { get; set; } = PriorityTypes.最低级;

		/// <summary>
		/// 初始化模板
		/// </summary>
		private const string TEMPLATE =
@"	attr.CMP_EN = ENABLE;								//允许比较器		ENABLE,DISABLE
	attr.CMP_P_Select     = CMP_P_{0};		//比较器输入正极选择, CMP_P_P37/CMP_P_P50/CMP_P_P51, CMP_P_ADC: 由ADC模拟输入端做正输入.
	attr.CMP_N_Select     = CMP_N_{1};		//比较器输入负极选择, CMP_N_GAP: 选择内部BandGap经过OP后的电压做负输入, CMP_N_P36: 选择P3.6做负输入.
	attr.CMP_InvCMPO      = {2};			//比较器输出取反, 	ENABLE,DISABLE
	attr.CMP_100nsFilter  = {3};			//内部0.1us滤波,  	ENABLE,DISABLE
	attr.CMP_Outpt_En     = {4};			//允许比较结果输出,ENABLE,DISABLE
	attr.CMP_OutDelayDuty = {5};					//比较结果变化延时周期数, 0~63
	{6}
	CMP_Inilize(&attr);				//初始化比较器
	NVIC_CMP_Init({7}, {8});	//中断使能, RISING_EDGE/FALLING_EDGE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3";

		public bool AppendConfig(List<string[]> aLst)
		{
			if (!this.Enable)
			{
				return false;
			}

			string name = "CMP_Config";
			StringBuilder tmpSb = new StringBuilder();
			tmpSb.Append(TemplateHelper.GetFunctionCommit("CMP模块初始化"));
			tmpSb.AppendLine($"PRIVATE void {name}(void)").AppendLine("{");
			tmpSb.AppendLine("\tCMP_InitDefine attr;");

			// 引脚初始化
			Dictionary<string, List<string>> lst = new Dictionary<string, List<string>>();
			if (this.Positive != CMPPositive.ADC输入)
			{
				var opt = mParent.GetPinOption(this.Positive.ToDescription());
				if (opt != null)
				{
					opt.ToSTC8Dictionary(lst);
				}
			}
			if (this.Negative != CMPNegative.内部参考电压)
			{
				var opt = mParent.GetPinOption(this.Negative.ToDescription());
				if (opt != null)
				{
					opt.ToSTC8Dictionary(lst);
				}
			}
			if (this.Out != CMPResultOut.不输出)
			{
				var opt = mParent.GetPinOption(this.Out.ToDescription());
				if (opt != null)
				{
					opt.ToSTC8Dictionary(lst);
				}
			}
			if (lst.Count > 0)
			{
				tmpSb.AppendLine();
				tmpSb.Append(GPIOOptions.GetGPIOConfigs(lst));
			}

			string str = string.Empty;
			if (this.EnablePTI)
			{
				str = "RISING_EDGE";
			}
			if (this.EnableNTI)
			{
				if (string.IsNullOrEmpty(str))
				{
					str = "FALLING_EDGE";
				}
				else
				{
					str += " | FALLING_EDGE";
				}
			}
			if (string.IsNullOrEmpty(str))
			{
				str = false.ToEnable();
			}

			tmpSb.AppendLine();
			string outStr = string.Empty;
			if (this.Out != CMPResultOut.不输出)
			{
				outStr = $"CMPO_{this.Out}();";
			}
			tmpSb.AppendFormat(TEMPLATE, this.Positive == CMPPositive.ADC输入 ? "ADC" : this.Positive.ToString(),
							this.Negative == CMPNegative.内部参考电压 ? "GAP" : this.Negative.ToString(),
							EnableReverse.ToEnable(), EnableFilter.ToEnable(), (this.Out != CMPResultOut.不输出).ToEnable(),
							this.DelayDuty, outStr, str, this.Priority.ToDescription()).AppendLine();
			tmpSb.AppendLine("}");

			aLst.Add(new String[] { tmpSb.ToString(), $"{name}();" });
			return true;
		}

		public CMPOptions(STC8HUSOP20 aParent)
		{
			this.mParent = aParent;
		}
	}
}
